/**
 * Control Node Used In Control Tree Structures
 * @author mpike
 */
ControlNode = new Class({
	
	_type : "ControlNode",
	
	Implements : [Options,Events],
	
	options : {
		title : '',
		parentNode : null,
		isActive : false,
		width 	: 50,
		height 	: 50,
		visible : false,
	},
	
	_private : {
		renderedChildCnt : 0,
		direction : null
	},
	
	childNodes : [],
	rootNode : null,
	element : null,
	x : null,
	y : null,
	
	initialize : function(options,isRoot){
		this.setOptions(options);
		this.element = new Element('a',{'class':'controlNode','title':this.options.title});
		if(isRoot){
			this.rootNode = this;
			this.setCurrent();
		}
	},
	
	getParentNode : function(){
		return this.options.parentNode;
	},
	
	isRootNode : function(){
		return this.getRootNode() ? true : false;
	},
	
	getRootNode : function(){
		return this.rootNode;
	},
	
	/**
	 * Set Active (an entire branch can be active)
	 */
	setActive : function(){
		this.isActive = true;
		this.fireEvent('selectControl');
	},
	
	/**
	 * Set Current (the one you are currently selecting)
	 */
	setCurrent : function(){
		// make sure parents are setActive and children are not active
		this.element.addClass("current");
	},

	show : function(){
		
	},
	
	hide : function(){
		// hide this plus child nodes
	},
	
	/**
	 * Add Child Node To Current
	 */
	addChild : function(node){
		node.parentNode = this;
		node.rootNode = this.getRootNode();
		this.childNodes.include(node);
	},
	
	toElement : function(){
		return this.element;
	},
	
	/**
	 * Set position of a node.. assuming root node is [0,0], a north east would be [1,-1]
	 */
	setPosition : function(xPos,yPos){
		this.x = xPos;
		this.y = yPos;
		if(xPos===0 && yPos===0){
			this.element.setStyles({'left':'300px','top':'300px'})
		}else{
			var root = this.getRootNode();
			var currLeft 	= (root.element.getStyle('left')).removePx();
			var currTop 	= (root.element.getStyle('top')).removePx();
			this.element.setStyles({'left':(currLeft+(xPos*this.options.width))+'px','top':(currTop+(yPos*this.options.height))+'px'});
		}
	},
	
	/**
	 * Render Control Structure
	 */
	render : function(){
		var body = $(document.body);
		//var branches = ['N','E','S','W'];
		this.renderNode(this,0,body,0,0,null);
	},
	
	/**
	 * Check to see a child node already exists at virtual coordinates
	 */
	childNodeExistsAt : function(chkX,chkY){
		for(var n=0;n<this.childNodes.length;n++){
			if(this.childNodes[n].x===chkX && this.childNodes[n].y===chkY) return true;
		}
		return false;
	},
	
	/**
	 * Render a single node in the tree, calls itself recursively to draw child nodes
	 * 
	 * @param ControlNode node e.g parent node that then renders children
	 * @param int level
	 * @param Element container
	 * @param int x Virtual coordinates e.g. [0,0] is root, [0,1] is South one unit
	 * @param int y
	 * @param string dir Direction branch is moving
	 */
	renderNode : function(node,level,container,x,y,dir){
		
		// Add Node To Container And Position 
		container.adopt(node.element);
		node._private.direction = dir;
		node.setPosition(x,y);
		node._private.level = level;
		// @todo debug remove...
		node.element.set("x",x); node.element.set("y",y);
		
		// Recursively Add Child Nodes
		for(var n=0;n<node.childNodes.length;n++){
			if(node._private.level===0){									// For children of the root node, position distributed
				var moveX = 0;
				var moveY = 0;
				var dir = null;
				switch(this._private.renderedChildCnt){
					case 0: moveX = -1;	moveY = 0; dir = 'W';	break; 	// West
					case 1: moveX = 1;	moveY = 0; dir = 'E';	break; 	// East
					case 2: moveX = 0;	moveY =-1; dir = 'N';	break; 	// North
					case 3: moveX = 0;	moveY = 1; dir = 'S';	break; 	// South
				}
			}else{											// For children of other children, distribute adjacent to that node and at a tangent to root node
				var moveX = x;
				var moveY = y;
				switch(dir){
					case 'N':
						moveY = moveY - 1;
						var n = 0;
						var dist = 0; // horiz distance from starting point 
						while(node.childNodeExistsAt(moveX,moveY)){ // Try coordinates to check for existing nodes before placing
							if(n%2){
								moveX = x + dist;
							}else{
								dist++;
								moveX = x - dist;
							}
							n++;
						}
						break;
					case 'E':
						moveX = moveX + 1;
						var n = 0;
						var dist = 0; // vertical distance from starting point 
						while(node.childNodeExistsAt(moveX,moveY)){ // Try coordinates to check for existing nodes before placing
							if(n%2){
								moveY = y + dist;
							}else{
								dist++;
								moveY = y - dist;
							}
							n++;
						}
						break;
					case 'S':
						moveY = moveY + 1;
						var n = 0;
						var dist = 0; // horiz distance from starting point 
						while(node.childNodeExistsAt(moveX,moveY)){ // Try coordinates to check for existing nodes before placing
							if(n%2){
								moveX = x + dist;
							}else{
								dist++;
								moveX = x - dist;
							}
							n++;
						}
						break;
					case 'W':
						moveX = moveX - 1;
						var n = 0;
						var dist = 0; // vertical distance from starting point 
						while(node.childNodeExistsAt(moveX,moveY)){ // Try coordinates to check for existing nodes before placing
							if(n%2){
								moveY = y + dist;
							}else{
								dist++;
								moveY = y - dist;
							}
							n++;
						}
						break;
				}
			}
			this.renderNode(node.childNodes[n],(node._private.level+1),container,moveX,moveY,dir);
			this._private.renderedChildCnt++;
		}
	}
});